home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
kernel
/
recov
/
recovFast.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-18
|
55KB
|
2,007 lines
/*
* recovFast.c --
*
* The routines here deal with fast restart and recovery from an
* area of memory preserved across crashes.
*
* Copyright 1987 Regents of the University of California
* All rights reserved.
*/
#ifndef lint
static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/recov/recovFast.c,v 9.4 92/12/13 18:20:11 mgbaker Exp $ SPRITE (Berkeley)";
#endif /* not lint */
#include <sprite.h>
#include <recov.h>
#include <mach.h>
#include <machConst.h>
#include <sync.h>
#include <stdio.h>
#include <vm.h>
#include <stdlib.h>
#define NUM_RESTART_TYPES 10
/*
* Info per/object about what its checksum is, if it's allocated, or what
* the next free index is if it's not allocated.
*/
typedef struct ObjInfo {
short applObjNum;
union {
unsigned short checksum;
unsigned short nextFree;
} info;
} ObjInfo;
/*
* Per-type information kept in the table of contents. The objects for a type
* are stored as if in an array, indexed by the object's number. The bitmap
* for a type shows the allocation of objects in the object array. It also
* gives the application's object number for the object, if there is one.
* The value in the array for an object can be 0 (unallocated), or -1 (allocated
* without an application object number, or else give the application's
* object number.
*/
typedef struct RestartTypeInfo {
int objectSize; /* Size of this type's objects. */
int maxNumObjects; /* Max possible objects at once. */
int currentNum; /* Current num of objects for type. */
int applicationTypeID; /* Application's type ID. */
int firstFree; /* First index in free obj buffer. */
ObjInfo *objInfoAddr; /* Address of checksum/free array. */
char *objectsAddr; /* Address of object storage. */
unsigned short (*Checksum)(); /* Function to use to generate checksum.
* No checksum done if NIL. */
} RestartTypeInfo;
typedef struct RestartHeader {
int initialized;
int nextTypeID;
RestartTypeInfo contents[NUM_RESTART_TYPES];
} RestartHeader;
RestartHeader *restartTablePtr;
static int spaceUsed;
/*
* Used for saving past values of checksum routines for the different
* object types when the checksum is toggled on and off for testing.
*/
Address checksumList[NUM_RESTART_TYPES] =
{(Address) NIL, (Address) NIL,
(Address) NIL, (Address) NIL,
(Address) NIL, (Address) NIL,
(Address) NIL, (Address) NIL,
(Address) NIL, (Address) NIL};
Boolean recov_RestartDebug = FALSE;
static unsigned short GetFreeIndex _ARGS_((int typeID));
static void AddFreeIndex _ARGS_((int typeID, int objNum));
static Sync_Lock restartTableLock;
#define LOCKPTR (&restartTableLock)
/*
*----------------------------------------------------------------------
*
* Recov_InitRecovBox --
*
* Initialize fast recovery code.
*
* Results:
* Whether or not box was already initialized. (TRUE if done already.)
*
* Side effects:
* Recovery area and data structures are initialized.
*
*----------------------------------------------------------------------
*/
Boolean
Recov_InitRecovBox()
{
Boolean alreadyInit = FALSE;
int nextID;
restartTablePtr = (RestartHeader *) mach_RestartTablePtr;
if (recov_RestartDebug) {
printf("mach_RestartTablePtr is at 0x%x\n");
}
if (restartTablePtr == (RestartHeader *) NIL ||
restartTablePtr == (RestartHeader *) NULL) {
panic("Recov_InitRecovBox called with no restart table available.");
}
if ((Mach_GetRestartTableSize() & (VMMACH_PAGE_SIZE -1)) != 0) {
panic(
"Recov_Init_RecovBox: restart table not multiple of page size.\n");
}
if (((unsigned int) restartTablePtr & (VMMACH_PAGE_SIZE - 1)) != 0) {
panic(
"Recov_Init_RecovBox: restart table not aligned on page boundary.\n");
}
/*
* Check if we've been initialized before.
*/
if (!restartTablePtr->initialized) {
/* Uninitialized - set everything to zero. */
bzero((char *) restartTablePtr, Mach_GetRestartTableSize());
spaceUsed = sizeof (RestartHeader);
if (recov_RestartDebug) {
printf("Recov_InitRecovBox: initialized, addr 0x%x.\n",
(char *) restartTablePtr);
}
} else {
alreadyInit = TRUE;
/* The nextTypeID is stored in table and needs no initialization. */
nextID = restartTablePtr->nextTypeID;
/* set spaceUsed */
if (nextID == 0) {
spaceUsed = 0;
} else {
spaceUsed = (unsigned int)
restartTablePtr->contents[nextID - 1].objectsAddr +
(restartTablePtr->contents[nextID - 1].maxNumObjects *
restartTablePtr->contents[nextID - 1].objectSize) -
(unsigned int) restartTablePtr;
}
if (recov_RestartDebug) {
printf("Recov_InitRecovBox: already initialized, addr 0x%x.\n",
(char *) restartTablePtr);
}
}
restartTablePtr->initialized = 1;
return alreadyInit;
}
/*
*----------------------------------------------------------------------
*
* Recov_ToggleChecksum --
*
* Toggle whether checksum is done or not for type .
*
* Results:
* Number of objects, given their size and the fact that there must be
* a bitmap of their allocation, etc.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
Recov_ToggleChecksum(typeID)
int typeID;
{
unsigned short (*save)();
if (!recov_Transparent) {
printf("Recov_ToggleChecksum: no transparent recovery.\n");
return;
}
save = restartTablePtr->contents[typeID].Checksum;
restartTablePtr->contents[typeID].Checksum =
(unsigned short (*)()) checksumList[typeID];
checksumList[typeID] = (Address) save;
if (save != (unsigned short (*)()) NIL) {
printf("Checksum turned off.\n");
} else {
printf("Checksum turned on.\n");
}
return;
}
/*
*----------------------------------------------------------------------
*
* GetFreeIndex --
*
* Get the index of the next free object space. Take it off free list.
*
* Results:
* The index of the free object space.
*
* Side effects:
* Takes object off free list.
*
*----------------------------------------------------------------------
*/
static unsigned short
GetFreeIndex(typeID)
int typeID;
{
unsigned short freeIndex;
RestartTypeInfo *typeInfoPtr;
if (!recov_Transparent) {
panic("GetFreeIndex: no transparent recovery.");
}
typeInfoPtr = &(restartTablePtr->contents[typeID]);
freeIndex = typeInfoPtr->firstFree;
typeInfoPtr->firstFree = typeInfoPtr->objInfoAddr[freeIndex].info.nextFree;
return freeIndex;
}
/*
*----------------------------------------------------------------------
*
* AddFreeIndex --
*
* Add an object to the free list.
*
* Results:
* None.
*
* Side effects:
* Object goes at head of free list.
*
*----------------------------------------------------------------------
*/
static void
AddFreeIndex(typeID, objNum)
int typeID;
int objNum;
{
RestartTypeInfo *typeInfoPtr;
if (!recov_Transparent) {
panic("AddFreeIndex: no transparent recovery.");
}
typeInfoPtr = &(restartTablePtr->contents[typeID]);
typeInfoPtr->objInfoAddr[objNum].info.nextFree = typeInfoPtr->firstFree;
typeInfoPtr->firstFree = objNum;
return;
}
/*
*----------------------------------------------------------------------
*
* Recov_MaxNumObjects --
*
* Figure out how many objects of this new size can be put into the table.
* If it's a fast restart, figure out how many total objects would fit
* into the table assuming this is the first type.
*
* Results:
* Number of objects, given their size and the fact that there must be
* a bitmap of their allocation, etc.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
Recov_MaxNumObjects(objectSize, restart)
int objectSize;
Boolean restart; /* If this is a fast restart. */
{
int spaceLeft;
int maxNumObjects;
if (!recov_Transparent) {
printf("Recov_MaxNumObjects: no transparent recovery.\n");
return 0;
}
if (!restartTablePtr->initialized) {
panic("Recov_MaxNumObjects called before Recov_InitRecovBox.");
}
/*
* If this is a fast restart, spaceUsed includes everything in the table
* already and we'd get told we had room for almost no objects, but what
* we want on a fast restart is how many objects (old and new) the table
* will hold, so we do the calculation differently. But this only works
* for the first type allocated after the restart!
*/
if (restart) {
spaceLeft = Mach_GetRestartTableSize() - sizeof (RestartHeader);
} else {
spaceLeft = Mach_GetRestartTableSize() - spaceUsed;
}
/*
* This includes space for the objects and their checksum/freelist array
* and a word alignment.
*/
maxNumObjects = (spaceLeft - sizeof (int)) / (objectSize + sizeof (int));
return maxNumObjects;
}
/*
*----------------------------------------------------------------------
*
* Recov_PrintSpace --
*
* Print out how much space is taken by what in the recovery box.
*
* Results:
* None.
*
* Side effects:
* Prints out the result.
*
*----------------------------------------------------------------------
*/
void
Recov_PrintSpace(objectSize)
int objectSize;
{
int spaceLeft;
int maxNumObjects;
if (!recov_Transparent) {
printf("Recov_PrintSpace: no transparent recovery.\n");
return;
}
if (!restartTablePtr->initialized) {
panic("Recov_PrintSpace called before Recov_InitRecovBox.");
}
/*
*/
printf("Sizes:\n");
printf("Header:\t%d\t0x%x\n", sizeof (RestartHeader),
sizeof (RestartHeader));
spaceLeft = Mach_GetRestartTableSize() - sizeof (RestartHeader);
printf("ObjSpace:\t%d\t0x%x\n", spaceLeft, spaceLeft);
spaceLeft = Mach_GetRestartTableSize() - spaceUsed;
printf("SpaceLeft:\t%d\t0x%x\n", spaceLeft, spaceLeft);
/*
* This includes space for the objects and their allocation bitmap
* and a word alignment.
*/
maxNumObjects = (spaceLeft - sizeof (int)) / (objectSize + sizeof (int));
printf("This is room for %d (0x%x) objs of size %d with allocation map.\n",
maxNumObjects, maxNumObjects, objectSize);
return;
}
/*
*----------------------------------------------------------------------
*
* Recov_InitType --
*
* Initialize fast recovery area for a new object type.
*
* Results:
* SUCCESS or FAILURE. If successful we also return in objectTypeIDPtr
* the type ID for this new object type if there are no errors, or
* an error code (-1) if this does not work. Reasons for failure are too
* many object types already, not enough space for the desired number
* of objects or an object size of zero, or else that the given
* application type ID is positive (set) and turns out not to be unique.
*
* Side effects:
* A portion of the recovery area is set aside.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Recov_InitType(objectSize, maxNumObjects, applicationTypeID, objectTypePtr,
Checksum)
int objectSize;
int maxNumObjects;
int applicationTypeID;
int *objectTypePtr; /* OUT: new object typeId
* if successful. */
unsigned short (*Checksum)(); /* No Checksum if 0 or NIL, use
* default if == 1. */
{
int spaceLeft;
unsigned int mask;
int i;
RestartTypeInfo *typeInfoPtr;
int typeID;
LOCK_MONITOR;
if (recov_RestartDebug) {
printf("Recov_InitType: objectSize: %d, maxNumObjects: %d\n",
objectSize, maxNumObjects);
}
if (!recov_Transparent) {
printf("Recov_InitType: no transparent recovery.\n");
UNLOCK_MONITOR;
return FAILURE;
}
if (objectSize <= 0) {
printf("Recov_InitType: Cannot accept 0-sized object type.\n");
UNLOCK_MONITOR;
return FAILURE;
}
/*
* Check if there are still slots for new object types.
*/
*objectTypePtr = -1;
if (restartTablePtr->nextTypeID >= NUM_RESTART_TYPES) {
printf("Recov_InitType: No space for a new restart object type.\n");
UNLOCK_MONITOR;
return FAILURE;
}
typeID = restartTablePtr->nextTypeID;
if (applicationTypeID > 0) {
for (i = 0; i < typeID; i++) {
if (restartTablePtr->contents[i].applicationTypeID ==
applicationTypeID) {
printf("Recov_InitType: applicationTypeID %d is not unique.\n",
applicationTypeID);
UNLOCK_MONITOR;
return FAILURE;
}
}
}
/*
* Check if there's space for the desired number of objects.
*/
spaceLeft = Mach_GetRestartTableSize() - spaceUsed;
if (recov_RestartDebug) {
printf("Recov_InitType: space used: 0x%x, space left now: 0x%x\n",
spaceUsed, spaceLeft);
}
/*
* Is there enough space for the new objects plus a bitmap
* of their allocation? (Plus a word for alignment for the bitmap.)
*/
if (Recov_MaxNumObjects(objectSize, 0) < maxNumObjects) {
printf("Recov_InitType: Not enough space left for request.\n");
UNLOCK_MONITOR;
return FAILURE;
}
/*
* Allocate new object type space.
*/
typeInfoPtr = &(restartTablePtr->contents[typeID]);
typeInfoPtr->objectSize = objectSize;
typeInfoPtr->applicationTypeID = applicationTypeID;
typeInfoPtr->maxNumObjects = maxNumObjects;
typeInfoPtr->currentNum = 0;
typeInfoPtr->objInfoAddr = (ObjInfo *) (((char *) restartTablePtr) +
spaceUsed + sizeof (int));
/* Word-align the checksum/freelist array. */
mask = sizeof (int) - 1;
typeInfoPtr->objInfoAddr = (ObjInfo *)
(((unsigned int) typeInfoPtr->objInfoAddr) & ~mask);
typeInfoPtr->objectsAddr = (char *)
(((char *) typeInfoPtr->objInfoAddr) +
(maxNumObjects * sizeof (ObjInfo)));
if (recov_RestartDebug) {
printf("Recov_InitType: objInfoAddr: 0x%x, objectsAddr: 0x%x\n",
typeInfoPtr->objInfoAddr, typeInfoPtr->objectsAddr);
}
spaceUsed = (unsigned int) typeInfoPtr->objectsAddr +
(maxNumObjects * objectSize) - (unsigned int) restartTablePtr;
if (Checksum == (unsigned short (*)()) 0) {
typeInfoPtr->Checksum = (unsigned short (*)()) NIL;
} else if (Checksum == (unsigned short (*)()) 1) {
typeInfoPtr->Checksum = Recov_Checksum;
} else {
typeInfoPtr->Checksum = Checksum;
}
/* Set up free list. */
typeInfoPtr->firstFree = 0;
for (i = 0; i < maxNumObjects - 1; i++) {
typeInfoPtr->objInfoAddr[i].info.nextFree = i + 1;
}
/* Point back to beginning of array. */
typeInfoPtr->objInfoAddr[maxNumObjects - 1].info.nextFree = 0;
*objectTypePtr = typeID;
if (recov_RestartDebug) {
printf("Recov_InitType: new object type %d\n", *objectTypePtr);
}
restartTablePtr->nextTypeID++;
UNLOCK_MONITOR;
return SUCCESS;
}
/*
*----------------------------------------------------------------------
*
* Recov_GetObjectSize --
*
* Return the object size for a given type of objects.
*
* Results:
* The size of an object of the given type. -1 if there is no such
* type.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
Recov_GetObjectSize(typeID)
int typeID; /* Type of object to insert. */
{
int objectSize;
LOCK_MONITOR;
if (!recov_Transparent) {
printf("Recov_GetObjectSize: no transparent recovery.\n");
UNLOCK_MONITOR;
return -1;
}
if (typeID < 0 || typeID >= restartTablePtr->nextTypeID) {
UNLOCK_MONITOR;
return -1;
}
objectSize = restartTablePtr->contents[typeID].objectSize;
UNLOCK_MONITOR;
return objectSize;
}
/*
*----------------------------------------------------------------------
*
* Recov_InsertObject --
*
* Insert an object into the recovery area.
*
* Results:
* SUCCESS or FAILURE. Reasons for failure are that the object type
* doesn't exist or that the area for this object type is already
* filled.
*
* Side effects:
* If successful, a new object is recorded in the recovery area.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Recov_InsertObject(typeID, objectPtr, applicationObjectNum, objectIDPtr)
int typeID; /* Type of object to insert. */
ClientData objectPtr; /* The object. */
int applicationObjectNum; /* The appl's number for obj. */
Recov_ObjectID *objectIDPtr; /* OUT: ID of new object. */
{
int i;
RestartTypeInfo *restartTypeInfoPtr;
ObjInfo *objInfoAddr;
int objectSize;
char *addr;
int freeIndex;
LOCK_MONITOR;
objectIDPtr->typeID = -1;
objectIDPtr->objectNumber = -1;
if (!recov_Transparent) {
printf("Recov_InsertObject: no transparent recovery.\n");
UNLOCK_MONITOR;
return FAILURE;
}
if (typeID < 0 || typeID >= restartTablePtr->nextTypeID) {
printf("Recov_InsertObject: No such fast restart object type.\n");
UNLOCK_MONITOR;
return FAILURE;
}
restartTypeInfoPtr = &(restartTablePtr->contents[typeID]);
if (restartTypeInfoPtr->currentNum >=
restartTypeInfoPtr->maxNumObjects) {
printf("Recov_InsertObject: No space for another such object.\n");
UNLOCK_MONITOR;
return FAILURE;
}
/* Get a free index. */
freeIndex = GetFreeIndex(typeID);
objInfoAddr = restartTypeInfoPtr->objInfoAddr;
if (applicationObjectNum <= 0) {
objInfoAddr[freeIndex].applObjNum = -1;
} else {
/* Should I really check? This will make it a lot slower. */
for (i = 0; i < restartTypeInfoPtr->maxNumObjects; i++) {
if (objInfoAddr[i].applObjNum == applicationObjectNum) {
printf("Recov_InsertObject: Object num already used.\n");
UNLOCK_MONITOR;
return FAILURE;
}
}
objInfoAddr[freeIndex].applObjNum = applicationObjectNum;
}
objectSize = restartTypeInfoPtr->objectSize;
addr = restartTypeInfoPtr->objectsAddr + (freeIndex * objectSize);
if (restartTypeInfoPtr->Checksum != (unsigned short (*)()) NIL) {
volatile unsigned short sum;
/* Volatile should change when we check the checksum!!! */
sum = (*(restartTypeInfoPtr->Checksum))(objectSize,
(Address) objectPtr);
}
objectIDPtr->typeID = typeID;
objectIDPtr->objectNumber = freeIndex;
restartTypeInfoPtr->currentNum++;
bcopy((char *) objectPtr, addr, objectSize);
UNLOCK_MONITOR;
return SUCCESS;
}
/*
*----------------------------------------------------------------------
*
* Recov_InsertObjects --
*
* Insert a set of objects into the recovery area at once. If the
* objNumBuffer is not NIL, then this array gives the application's
* object numbers to record.
*
* Results:
* SUCCESS or FAILURE. Reasons for failure are that the object type
* doesn't exist or that the area for this object type is already
* filled. The objects' IDs are returned in the out-going buffer.
*
* Side effects:
* If successful, new objects are recorded in the recovery area.
* If the routine returns SUCCESS, then all the objects have been
* inserted. If it returns FAILURE, then no objects have been inserted.
* If it panics, then the results are undefined.
*
*
*----------------------------------------------------------------------
*/
ReturnStatus
Recov_InsertObjects(typeID, numObjs, obuffer, objNumBuffer, objIDBuffer)
int typeID; /* Type of object to insert. */
int numObjs; /* Number of objects to insert. */
char *obuffer; /* The objects. */
int *objNumBuffer; /* The appl's numbers for objs. */
Recov_ObjectID *objIDBuffer; /* OUT: IDs of new objects. */
{
int i, freeIndex;
RestartTypeInfo *restartTypeInfoPtr;
ObjInfo *objInfoAddr;
int objectSize;
char *addr;
Recov_ObjectID *objectIDPtr;
char *objectPtr;
LOCK_MONITOR;
if (!recov_Transparent) {
printf("Recov_InsertObjects: no transparent recovery.\n");
UNLOCK_MONITOR;
return FAILURE;
}
/* Should I bother to do this? */
for (i = 0; i < numObjs; i++) {
objIDBuffer[i].typeID = -1;
objIDBuffer[i].objectNumber = -1;
}
if (typeID < 0 || typeID >= restartTablePtr->nextTypeID) {
printf("Recov_InsertObjects: No such fast restart object type.\n");
UNLOCK_MONITOR;
return FAILURE;
}
restartTypeInfoPtr = &(restartTablePtr->contents[typeID]);
if (restartTypeInfoPtr->currentNum + numObjs >
restartTypeInfoPtr->maxNumObjects) {
printf("Recov_InsertObjects: Not enough space for new objects.\n");
UNLOCK_MONITOR;
return FAILURE;
}
objInfoAddr = restartTypeInfoPtr->objInfoAddr;
if (objNumBuffer != (int *) NIL) {
/* Should I really check? This will make it a lot slower. */
for (i = 0; i < numObjs; i++) {
for (i = 0; i < restartTypeInfoPtr->maxNumObjects; i++) {
if (objInfoAddr[i].applObjNum == objNumBuffer[i]) {
printf("Recov_InsertObjects: Object num %d already used.\n",
objNumBuffer[i]);
UNLOCK_MONITOR;
return FAILURE;
}
}
}
}
objectSize = restartTypeInfoPtr->objectSize;
/* Get first empty slot. */
freeIndex = GetFreeIndex(typeID);
for (i = 0; i < numObjs; i++) {
if (objNumBuffer != (int *) NIL) {
objInfoAddr[freeIndex].applObjNum = objNumBuffer[i];
} else {
objInfoAddr[freeIndex].applObjNum = -1;
}
objectIDPtr = &(objIDBuffer[i]);
objectIDPtr->typeID = typeID;
objectIDPtr->objectNumber = freeIndex;
restartTypeInfoPtr->currentNum++;
objectPtr = obuffer + (objectSize * i);
addr = restartTypeInfoPtr->objectsAddr + (freeIndex * objectSize);
if (restartTypeInfoPtr->Checksum != (unsigned short (*)()) NIL) {
volatile unsigned short sum;
/* Volatile should change when we check the checksum!!! */
sum = (*(restartTypeInfoPtr->Checksum))(objectSize,
(Address) objectPtr);
}
bcopy((char *) objectPtr, addr, objectSize);
/* Find next empty slot. */
freeIndex = GetFreeIndex(typeID);
}
UNLOCK_MONITOR;
return SUCCESS;
}
/*
*----------------------------------------------------------------------
*
* Recov_DeleteObject --
*
* Delete an object from the recovery area.
*
* Results:
* SUCCESS or FAILURE. Reasons for failure are that the object type
* doesn't exist or that the object doesn't exist.
*
* Side effects:
* If successful, an object space is freed up.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Recov_DeleteObject(objectID)
Recov_ObjectID objectID; /* ID of object to remove. */
{
ObjInfo *objInfoAddr;
char *addr;
int objectSize;
RestartTypeInfo *restartTypeInfoPtr;
LOCK_MONITOR;
if (!recov_Transparent) {
printf("Recov_DeleteObject: no transparent recovery.\n");
UNLOCK_MONITOR;
return FAILURE;
}
restartTypeInfoPtr =
&(restartTablePtr->contents[objectID.typeID]);
if (objectID.typeID < 0 || objectID.typeID >= restartTablePtr->nextTypeID) {
printf("Recov_DeleteObject: bad typeID.\n");
UNLOCK_MONITOR;
return FAILURE;
}
if (objectID.objectNumber < 0 ||
objectID.objectNumber > restartTypeInfoPtr->maxNumObjects) {
printf("Recov_DeleteObject: bad object number.\n");
UNLOCK_MONITOR;
return FAILURE;
}
if (restartTypeInfoPtr->objectSize <= 0) {
printf("Recov_DeleteObject: bad object type.\n");
UNLOCK_MONITOR;
return FAILURE;
}
objInfoAddr = restartTypeInfoPtr->objInfoAddr;
if (objInfoAddr[objectID.objectNumber].applObjNum == 0) {
printf("Recov_DeleteObject: object doesn't exist.\n");
UNLOCK_MONITOR;
return FAILURE;
}
objInfoAddr[objectID.objectNumber].applObjNum = 0;
AddFreeIndex(objectID.typeID, objectID.objectNumber);
objectSize = restartTypeInfoPtr->objectSize;
restartTypeInfoPtr->currentNum--;
if (restartTypeInfoPtr->currentNum < 0) {
UNLOCK_MONITOR;
panic("Recov_DeleteObject: less than zero objects of a type.\n");
}
addr = restartTypeInfoPtr->objectsAddr +
(objectID.objectNumber * objectSize);
/* Not really necessary, but helpful for debugging. */
bzero(addr, objectSize);
UNLOCK_MONITOR;
return SUCCESS;
}
/*
*----------------------------------------------------------------------
*
* Recov_UpdateObject --
*
* Update an object in the recovery area.
*
* Results:
* SUCCESS or FAILURE. Reasons for failure are that the object type
* doesn't exist or that the object doesn't exist.
*
* Side effects:
* If successful, an object is updated.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Recov_UpdateObject(objectPtr, objectID)
ClientData objectPtr; /* New value of object. */
Recov_ObjectID objectID; /* ID of object to update. */
{
ObjInfo *objInfoAddr;
char *addr;
RestartTypeInfo *restartTypeInfoPtr;
int objectSize;
LOCK_MONITOR;
if (!recov_Transparent) {
printf("Recov_UpdateObject: no transparent recovery.\n");
UNLOCK_MONITOR;
return FAILURE;
}
restartTypeInfoPtr =
&(restartTablePtr->contents[objectID.typeID]);
if (objectID.typeID < 0 || objectID.typeID >= restartTablePtr->nextTypeID) {
printf("Recov_UpdateObject: bad typeID.\n");
UNLOCK_MONITOR;
return FAILURE;
}
if (objectID.objectNumber < 0 ||
objectID.objectNumber > restartTypeInfoPtr->maxNumObjects) {
printf("Recov_UpdateObject: bad object number.\n");
UNLOCK_MONITOR;
return FAILURE;
}
if (restartTypeInfoPtr->objectSize <= 0) {
printf("Recov_UpdateObject: bad object type.\n");
UNLOCK_MONITOR;
return FAILURE;
}
objInfoAddr = restartTypeInfoPtr->objInfoAddr;
if (objInfoAddr[objectID.objectNumber].applObjNum == 0) {
printf("Recov_UpdateObject: object doesn't exist.\n");
UNLOCK_MONITOR;
return FAILURE;
}
objectSize = restartTypeInfoPtr->objectSize;
addr = restartTypeInfoPtr->objectsAddr +
(objectID.objectNumber * objectSize);
if (restartTypeInfoPtr->Checksum != (unsigned short (*)()) NIL) {
volatile unsigned short sum;
/* XXX Volatile should change when we check the checksum!!! */
sum = (*(restartTypeInfoPtr->Checksum))(objectSize,
(Address) objectPtr);
}
bcopy((char *) objectPtr, addr, objectSize);
UNLOCK_MONITOR;
return SUCCESS;
}
/*
*----------------------------------------------------------------------
*
* Recov_ReturnObject --
*
* Return the value of a single object.
*
* Results:
* SUCCESS or FAILURE. Reasons for failure are that the object type
* doesn't exist or that the object doesn't exist.
*
* Side effects:
* If successful, an object is returned.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Recov_ReturnObject(objectPtr, objectID, checksum)
ClientData objectPtr; /* Ptr to return object. */
Recov_ObjectID objectID; /* ID of object to return. */
Boolean checksum;
{
ObjInfo *objInfoAddr;
char *addr;
RestartTypeInfo *restartTypeInfoPtr;
int objectSize;
LOCK_MONITOR;
if (!recov_Transparent) {
printf("Recov_ReturnObject: no transparent recovery.\n");
UNLOCK_MONITOR;
return FAILURE;
}
restartTypeInfoPtr =
&(restartTablePtr->contents[objectID.typeID]);
if (objectID.typeID < 0 || objectID.typeID >= restartTablePtr->nextTypeID) {
printf("Recov_ReturnObject: bad typeID.\n");
UNLOCK_MONITOR;
return FAILURE;
}
if (objectID.objectNumber < 0 ||
objectID.objectNumber > restartTypeInfoPtr->maxNumObjects) {
printf("Recov_ReturnObject: bad object number.\n");
UNLOCK_MONITOR;
return FAILURE;
}
if (restartTypeInfoPtr->objectSize <= 0) {
printf("Recov_ReturnObject: bad object type.\n");
UNLOCK_MONITOR;
return FAILURE;
}
objInfoAddr = restartTypeInfoPtr->objInfoAddr;
if (objInfoAddr[objectID.objectNumber].applObjNum == 0) {
printf("Recov_ReturnObject: object doesn't exist.\n");
UNLOCK_MONITOR;
return FAILURE;
}
objectSize = restartTypeInfoPtr->objectSize;
addr = restartTypeInfoPtr->objectsAddr +
(objectID.objectNumber * objectSize);
if (checksum && restartTypeInfoPtr->Checksum !=
(unsigned short (*)()) NIL) {
volatile unsigned short sum;
/* XXX Volatile should change when we check the checksum!!! */
sum = (*(restartTypeInfoPtr->Checksum))(objectSize, (Address) addr);
}
bcopy(addr, (char *) objectPtr, objectSize);
UNLOCK_MONITOR;
return SUCCESS;
}
/*
*----------------------------------------------------------------------
*
* Recov_ReturnObjects --
*
* Return an array of all the objects of a particular type. Also return
* an array of their object IDs if the id buffer is not NIL. Finally,
* return an array of the corresponding application object numbers if the
* application num buffer is not NIL.
*
* Results:
* SUCCESS or FAILURE. Reasons for failure are that the object type
* doesn't exist or that not enough space was handed to the routine.
* The lengthPtrs return the actual length of the buffers filled in.
*
* Side effects:
* If successful, an array of objects is returned in the object buffer
* and an array of object IDs in the object ID buffer (if not NIL),
* and an array of application's object numbers in the application object
* num buffer (if not NIL).
*
*----------------------------------------------------------------------
*/
ReturnStatus
Recov_ReturnObjects(typeID, olengthPtr, obuffer, ilengthPtr, ibuffer,
alengthPtr, abuffer)
int typeID; /* Type of objects to return. */
int *olengthPtr; /* IN/OUT: length of object buffer. */
char *obuffer; /* OUT: Buffer to put objects into. */
int *ilengthPtr; /* IN/OUT: length of object ID buffer. */
char *ibuffer; /* OUT: Buffer to put object IDs into. */
int *alengthPtr; /* IN/OUT: length of appl. obj. num buffer. */
char *abuffer; /* OUT: Buffer to put appl. obj. nums into. */
{
ObjInfo *objInfoAddr;
char *addr;
RestartTypeInfo *restartTypeInfoPtr;
int i;
int destNum;
int osizeNeeded;
int isizeNeeded = 0;
int asizeNeeded = 0;
LOCK_MONITOR;
if (!recov_Transparent) {
printf("Recov_ReturnObjects: no transparent recovery.\n");
UNLOCK_MONITOR;
return FAILURE;
}
restartTypeInfoPtr =
&(restartTablePtr->contents[typeID]);
if (typeID < 0 || typeID >= restartTablePtr->nextTypeID) {
printf("Recov_ReturnObjects: bad typeID.\n");
UNLOCK_MONITOR;
return FAILURE;
}
if (restartTypeInfoPtr->objectSize <= 0) {
printf("Recov_ReturnObjects: bad object type.\n");
UNLOCK_MONITOR;
return FAILURE;
}
osizeNeeded = restartTypeInfoPtr->currentNum *
restartTypeInfoPtr->objectSize;
if (*olengthPtr < osizeNeeded) {
printf("Recov_ReturnObjects: not enough space in object buffer.\n");
*olengthPtr = osizeNeeded;
UNLOCK_MONITOR;
return FAILURE;
}
if (ibuffer != (char *) NIL) {
isizeNeeded = restartTypeInfoPtr->currentNum *
sizeof (Recov_ObjectID);
if (*ilengthPtr < isizeNeeded) {
printf("Recov_ReturnObjects: not enough space in id buffer.\n");
*ilengthPtr = isizeNeeded;
UNLOCK_MONITOR;
return FAILURE;
}
}
if (abuffer != (char *) NIL) {
asizeNeeded = restartTypeInfoPtr->currentNum * sizeof (int);
if (*alengthPtr < asizeNeeded) {
printf("Recov_ReturnObjects: not enough space in appl. num buffer.\n");
*alengthPtr = asizeNeeded;
UNLOCK_MONITOR;
return FAILURE;
}
}
bzero(obuffer, *olengthPtr); /* Easier debugging if all bzeroed. */
*olengthPtr = osizeNeeded;
if (ibuffer != (char *) NIL) {
bzero(ibuffer, *ilengthPtr);
*ilengthPtr = isizeNeeded;
}
if (abuffer != (char *) NIL) {
bzero(abuffer, *alengthPtr);
*alengthPtr = asizeNeeded;
}
objInfoAddr = restartTypeInfoPtr->objInfoAddr;
destNum = 0;
addr = restartTypeInfoPtr->objectsAddr;
for (i = 0; i < restartTypeInfoPtr->maxNumObjects; i++) {
if (objInfoAddr[i].applObjNum != 0) {
if (restartTypeInfoPtr->Checksum != (unsigned short (*)()) NIL) {
volatile unsigned short sum;
/* Volatile should change when we check the checksum!!! */
sum = (*(restartTypeInfoPtr->Checksum))
(restartTypeInfoPtr->objectSize, (Address) addr);
}
/* copy object */
bcopy(addr, obuffer + (destNum * restartTypeInfoPtr->objectSize),
restartTypeInfoPtr->objectSize);
if (ibuffer != (char *) NIL) {
((Recov_ObjectID *) ibuffer)[destNum].typeID = typeID;
((Recov_ObjectID *) ibuffer)[destNum].objectNumber = i;
}
if (abuffer != (char *) NIL) {
((int *) abuffer)[destNum] = objInfoAddr[i].applObjNum;
}
destNum++;
}
addr += restartTypeInfoPtr->objectSize;
}
if (destNum > restartTypeInfoPtr->currentNum) {
UNLOCK_MONITOR;
panic("Recov_ReturnObjects: miscalculation of number of objects.");
}
UNLOCK_MONITOR;
return SUCCESS;
}
/*
*----------------------------------------------------------------------
*
* Recov_ReturnContents --
*
* Return the table of contents.
*
* Results:
* SUCCESS or FAILURE. The procedure can return failure if not enough
* buffer space is passed to it.
*
* Side effects:
* If successful, the table of contents is copied into the out param.
* The lengthPtr is filled in with the needed length of the buffer on
* both SUCCESS and FAILURE.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Recov_ReturnContents(lengthPtr, buffer)
int *lengthPtr; /* IN/OUT: length of buffer. */
char *buffer; /* OUT: Buffer to put table into. */
{
int i;
int sizeNeeded;
Recov_ContentsEntry *bufPtr;
RestartTypeInfo *restartTypeInfoPtr;
LOCK_MONITOR;
if (!recov_Transparent) {
printf("Recov_ReturnContents: no transparent recovery.\n");
UNLOCK_MONITOR;
return FAILURE;
}
for (i = 0; i < NUM_RESTART_TYPES; i++) {
if (restartTablePtr->contents[i].objectSize <= 0) {
break;
}
}
sizeNeeded = i * sizeof (Recov_ContentsEntry);
if (sizeNeeded > *lengthPtr) {
*lengthPtr = sizeNeeded;
printf("Recov_ReturnContents: not enough buffer space.\n");
UNLOCK_MONITOR;
return FAILURE;
}
*lengthPtr = sizeNeeded;
bufPtr = (Recov_ContentsEntry *) buffer;
for (i = 0; i < NUM_RESTART_TYPES; i++) {
if (restartTablePtr->contents[i].objectSize <= 0) {
break;
}
restartTypeInfoPtr = &(restartTablePtr->contents[i]);
bufPtr->objectSize = restartTypeInfoPtr->objectSize;
bufPtr->maxNumObjects = restartTypeInfoPtr->maxNumObjects;
bufPtr->applicationTypeID =
restartTypeInfoPtr->applicationTypeID;
bufPtr->currentNum = restartTypeInfoPtr->currentNum;
bufPtr->firstFree = restartTypeInfoPtr->firstFree;
bufPtr++;
}
UNLOCK_MONITOR;
return SUCCESS;
}
/*
*----------------------------------------------------------------------
*
* Recov_NumObjects --
*
* Return the current number of objects for given type.
*
* Results:
* The number, or -1 if something went wrong.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
Recov_NumObjects(typeID)
int typeID; /* IN: type of object to count. */
{
LOCK_MONITOR;
if (!recov_Transparent) {
printf("Recov_NumObjects: no transparent recovery.\n");
UNLOCK_MONITOR;
return -1;
}
if (typeID < 0 || typeID >= restartTablePtr->nextTypeID) {
return -1;
}
UNLOCK_MONITOR;
return restartTablePtr->contents[typeID].currentNum;
}
/*
*----------------------------------------------------------------------
*
* Recov_MapType --
*
* Return the real type used by the kernel given the application's
* type number;
*
* Results:
* SUCCESS or FAILURE. The procedure can return failure no such
* application type is found.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Recov_MapType(applicationTypeID, typeIDPtr)
int applicationTypeID; /* IN: Application's type number. */
int *typeIDPtr; /* OUT: Buffer to put type into. */
{
int i;
LOCK_MONITOR;
if (!recov_Transparent) {
printf("Recov_MapType: no transparent recovery.\n");
UNLOCK_MONITOR;
return FAILURE;
}
for (i = 0; i < restartTablePtr->nextTypeID; i++) {
if (restartTablePtr->contents[i].applicationTypeID ==
applicationTypeID) {
*typeIDPtr = i;
UNLOCK_MONITOR;
return SUCCESS;
}
}
*typeIDPtr = -1;
UNLOCK_MONITOR;
return FAILURE;
}
/*
*----------------------------------------------------------------------
*
* Recov_MapObjectNum --
*
* Return the real object number used by the kernel given the application's
* object number.
*
* Results:
* SUCCESS or FAILURE. The procedure can return failure no such
* application type or object number are found.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Recov_MapObjectNum(typeID, applicationObjectNum, objectNumPtr)
int typeID; /* The real type ID of the object. */
int applicationObjectNum; /* IN: Application's object num. */
int *objectNumPtr; /* OUT: Buffer to put obj num into. */
{
ObjInfo *objInfoAddr;
int i;
if (!recov_Transparent) {
printf("Recov_MapObjectNum: no transparent recovery.\n");
UNLOCK_MONITOR;
return FAILURE;
}
if (typeID < 0 || typeID >= restartTablePtr->nextTypeID) {
*objectNumPtr = -1;
return FAILURE;
}
LOCK_MONITOR;
objInfoAddr = restartTablePtr->contents[typeID].objInfoAddr;
for (i = 0; i < restartTablePtr->contents[typeID].maxNumObjects; i++) {
if (objInfoAddr[i].applObjNum == applicationObjectNum) {
*objectNumPtr = i;
UNLOCK_MONITOR;
return SUCCESS;
}
}
*objectNumPtr = -1;
UNLOCK_MONITOR;
return FAILURE;
}
/*
*----------------------------------------------------------------------
*
* Recov_Checksum --
*
* Compute the 16-bit one's complement of the 1's complement sum of
* of all words in the buffer.
*
* Note: It is assumed that the length of the buffer is at most
* 128K bytes long. It also helps if the buffer is word-aligned.
*
* Results:
* The 1's complement checksum in network byte-order.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
unsigned short
Recov_Checksum(len, bufPtr)
register int len; /* The number of bytes to checksum. */
Address bufPtr; /* What to checksum. */
{
register unsigned short *wordPtr = (unsigned short *) bufPtr;
register unsigned int sum = 0;
/*
* The basic algorithm 16-bit 1's complement addition is
* 1) add the two unsigned 16-bit quantities,
* 2) if there was a carry out of the high-order bit,
* it is added to the sum.
* To detect a carry out of the high-order bit, the sum is stored
* in a 32-bit word. As an optimization, we delay step 2 until
* all the words have been added together. At that point, the
* upper-half of the sum contains the sum of the carries from the
* additions. This value is then added to the lower half and if that
* operation causes a carry, then 1 is added to the sum.
*
* The optimization does place a limit on how many bytes can be
* summed without causing an overflow of the 32-bit sum. In the worst
* case, a maximum of 64K additions of 16-bit values can be added
* without overflow.
*
* The summation is done in an unrolled loop. Once we have less than
* 32 bytes to sum then it must be done in smaller loops.
*/
while (len >= 32) {
sum += *wordPtr++;
sum += *wordPtr++;
sum += *wordPtr++;
sum += *wordPtr++;
sum += *wordPtr++;
sum += *wordPtr++;
sum += *wordPtr++;
sum += *wordPtr++;
sum += *wordPtr++;
sum += *wordPtr++;
sum += *wordPtr++;
sum += *wordPtr++;
sum += *wordPtr++;
sum += *wordPtr++;
sum += *wordPtr++;
sum += *wordPtr++;
len -= 32;
}
while (len >= 2) {
sum += *wordPtr++;
len -= 2;
}
if (len == 1) {
#if BYTE_ORDER == LITTLE_ENDIAN
sum += (*wordPtr) & 0x00ff;
#else
sum += (*wordPtr) & 0xff00;
#endif
}
/*
* The most signficant bits of "sum" contains the carries from
* the overflow of the summing. Add this overflow back into
* the least significant 16 bits of the sum and do it a second
* time in case there's a carry from the first time.
*/
if (sum > 0xffff) {
sum = ((sum >> 16) & 0xffff) + (sum & 0xffff);
/*
* See if there was a carry from the addition. The overflow will
* be at most 1.
*/
if (sum > 0xffff) {
sum++;
}
}
return((~sum & 0xffff));
}
/*
*----------------------------------------------------------------------
*
* Recov_Cmd --
*
* Process user system call for doing recovery box operations.
* This is called via Sys_StatsStub and therefore has the same
* interface and user address pointers passed in.
*
* Results:
* SUCCESS or FAILURE.
*
* Side effects:
* May modify contents of recovery box.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Recov_Cmd(option, argPtr)
int option;
Address argPtr;
{
Recov_InitObjTypeArgs initArg;
Recov_InsertObjArgs insertArg;
Recov_InsertArrayArgs insertArrayArg;
Recov_DeleteObjArgs deleteArg;
Recov_UpdateObjArgs updateArg;
Recov_ReturnObjArgs returnArg;
Recov_ReturnArrayArgs returnArrayArg;
Recov_ReturnTableArgs returnContentsArg;
Recov_GetObjectSizeArgs getObjectSizeArg;
Recov_MapTypeArgs mapTypeArg;
Recov_MapObjectNumArgs mapObjNumArg;
ReturnStatus status = SUCCESS;
if (option != RECOV_TOGGLE_CHECKSUM &&
option != RECOV_PRINT_REBOOT_TIMES && option != RECOV_BULK_REOPEN
&& option != RECOV_SINGLE_REOPEN &&
option != RECOV_DO_SERVER_DRIVEN &&
option != RECOV_NO_SERVER_DRIVEN &&
(argPtr == (Address) NIL || argPtr == (Address) 0 ||
argPtr == (Address) USER_NIL)) {
return GEN_INVALID_ARG;
}
/* option is the command */
switch (option) {
case RECOV_INIT_OBJ_TYPE: {
status = Vm_CopyIn(sizeof (initArg), argPtr,
(Address) &initArg);
if (status != SUCCESS) {
break;
}
if (initArg.doChecksum != 0 && initArg.doChecksum != 1) {
status = GEN_INVALID_ARG;
break;
}
status = Recov_InitType(initArg.objectSize,
initArg.maxNumObjects, initArg.applicationTypeID,
&(initArg.objectType),
(unsigned short (*)())initArg.doChecksum);
if (status != SUCCESS) {
break;
}
status = Vm_CopyOut(sizeof (int),
(Address) &(initArg.objectType),
(Address) &(((Recov_InitObjTypeArgs *)
argPtr)->objectType));
break;
}
case RECOV_INSERT_OBJ: {
char *objectPtr;
int objectSize;
status = Vm_CopyIn(sizeof (insertArg), argPtr,
(Address) &insertArg);
if (status != SUCCESS) {
break;
}
if ((insertArg.objectPtr == (Address) NIL ||
insertArg.objectPtr == (Address) 0 ||
insertArg.objectPtr == (Address) USER_NIL)) {
status = GEN_INVALID_ARG;
break;
}
objectSize = Recov_GetObjectSize(insertArg.typeID);
if (objectSize == -1) {
status = GEN_INVALID_ARG;
break;
}
objectPtr = malloc(objectSize);
status = Vm_CopyIn(objectSize, insertArg.objectPtr,
(Address) objectPtr);
if (status != SUCCESS) {
free(objectPtr);
break;
}
status = Recov_InsertObject(insertArg.typeID,
(ClientData) objectPtr, insertArg.applicationObjectNum,
&(insertArg.objectID));
if (status != SUCCESS) {
free(objectPtr);
break;
}
status = Vm_CopyOut(sizeof (Recov_ObjectID),
(Address) &(insertArg.objectID),
(Address) &(((Recov_InsertObjArgs *)
argPtr)->objectID));
free(objectPtr);
break;
}
case RECOV_INSERT_ARRAY: {
char *objectBuffer;
int objectSize;
int *objNumBuffer;
Recov_ObjectID *objIDBuffer;
int numObjs;
status = Vm_CopyIn(sizeof (insertArrayArg), argPtr,
(Address) &insertArrayArg);
if (status != SUCCESS) {
break;
}
if (insertArrayArg.obuffer == (Address) NIL ||
insertArrayArg.obuffer == (Address) 0 ||
insertArrayArg.obuffer == (Address) USER_NIL) {
status = GEN_INVALID_ARG;
break;
}
objectSize = Recov_GetObjectSize(insertArrayArg.typeID);
if (objectSize == -1) {
status = GEN_INVALID_ARG;
break;
}
numObjs = insertArrayArg.numObjs;
objectBuffer = malloc(objectSize * numObjs);
status = Vm_CopyIn(objectSize * numObjs,
(Address) insertArrayArg.obuffer,
(Address) objectBuffer);
if (status != SUCCESS) {
free(objectBuffer);
break;
}
if (insertArrayArg.applObjNums == (int *) NIL ||
insertArrayArg.applObjNums == (int *) 0 ||
insertArrayArg.applObjNums == (int *) USER_NIL) {
objNumBuffer = (int *) NIL;
} else {
objNumBuffer = (int *) malloc(sizeof (int) * numObjs);
status = Vm_CopyIn(sizeof (int) * numObjs,
(Address) insertArrayArg.applObjNums,
(Address) objNumBuffer);
if (status != SUCCESS) {
free(objectBuffer);
free((char *) objNumBuffer);
break;
}
}
if (insertArrayArg.objIDBuffer == (Recov_ObjectID *) NIL ||
insertArrayArg.objIDBuffer == (Recov_ObjectID *) 0 ||
insertArrayArg.objIDBuffer ==
(Recov_ObjectID *) USER_NIL) {
status = GEN_INVALID_ARG;
free(objectBuffer);
if (objNumBuffer != (int *) NIL) {
free((char *) objNumBuffer);
}
break;
} else {
objIDBuffer = (Recov_ObjectID *)
malloc(sizeof (Recov_ObjectID) * numObjs);
}
status = Recov_InsertObjects(insertArrayArg.typeID, numObjs,
objectBuffer, objNumBuffer, objIDBuffer);
if (status != SUCCESS) {
free(objectBuffer);
if (objNumBuffer != (int *) NIL) {
free((char *) objNumBuffer);
}
free((char *) objIDBuffer);
break;
}
status = Vm_CopyOut(sizeof (Recov_ObjectID) * numObjs,
(Address) objIDBuffer,
(Address) insertArrayArg.objIDBuffer);
free((char *) objectBuffer);
if (objNumBuffer != (int *) NIL) {
free((char *) objNumBuffer);
}
free((char *) objIDBuffer);
break;
}
case RECOV_DELETE_OBJ: {
status = Vm_CopyIn(sizeof (deleteArg), argPtr,
(Address) &deleteArg);
if (status != SUCCESS) {
break;
}
status = Recov_DeleteObject(deleteArg.objectID);
break;
}
case RECOV_UPDATE_OBJ: {
char *objectPtr;
int objectSize;
status = Vm_CopyIn(sizeof (updateArg), argPtr,
(Address) &updateArg);
if (status != SUCCESS) {
break;
}
if ((updateArg.objectPtr == (Address) NIL ||
updateArg.objectPtr == (Address) 0 ||
updateArg.objectPtr == (Address) USER_NIL)) {
status = GEN_INVALID_ARG;
break;
}
objectSize = Recov_GetObjectSize(updateArg.objectID.typeID);
if (objectSize == -1) {
status = GEN_INVALID_ARG;
break;
}
objectPtr = malloc(objectSize);
status = Vm_CopyIn(objectSize, updateArg.objectPtr,
(Address) objectPtr);
if (status != SUCCESS) {
free(objectPtr);
break;
}
status = Recov_UpdateObject((ClientData) objectPtr,
updateArg.objectID);
free(objectPtr);
break;
}
case RECOV_RETURN_OBJ: {
char *objectPtr;
int objectSize;
status = Vm_CopyIn(sizeof (returnArg), argPtr,
(Address) &returnArg);
if (status != SUCCESS) {
break;
}
if (returnArg.objectPtr == (Address) NIL ||
returnArg.objectPtr == (Address) 0 ||
returnArg.objectPtr == (Address) USER_NIL) {
status = GEN_INVALID_ARG;
break;
}
objectSize = Recov_GetObjectSize(returnArg.objectID.typeID);
if (objectSize == -1) {
status = GEN_INVALID_ARG;
break;
}
objectPtr = malloc(objectSize);
status = Recov_ReturnObject((ClientData) objectPtr,
returnArg.objectID, TRUE);
if (status != SUCCESS) {
free(objectPtr);
break;
}
status = Vm_CopyOut(objectSize, (Address) objectPtr,
(Address) ((Recov_ReturnObjArgs *) argPtr)->objectPtr);
free(objectPtr);
break;
}
case RECOV_RETURN_ARRAY: {
char *newobuffer;
char *newibuffer;
char *newabuffer;
status = Vm_CopyIn(sizeof (returnArrayArg), argPtr,
(Address) &returnArrayArg);
if (status != SUCCESS) {
break;
}
if ((returnArrayArg.obuffer == (Address) NIL ||
returnArrayArg.obuffer == (Address) 0 ||
returnArrayArg.obuffer == (Address) USER_NIL)) {
status = GEN_INVALID_ARG;
break;
}
newobuffer = malloc(returnArrayArg.olength);
if ((returnArrayArg.ibuffer == (Address) NIL ||
returnArrayArg.ibuffer == (Address) 0 ||
returnArrayArg.ibuffer == (Address) USER_NIL)) {
returnArrayArg.ibuffer = (Address) NIL;
newibuffer = (char *) NIL;
} else {
if (returnArrayArg.ilength <= 0) {
free(newobuffer);
status = GEN_INVALID_ARG;
break;
}
newibuffer = malloc(returnArrayArg.ilength);
}
if ((returnArrayArg.abuffer == (Address) NIL ||
returnArrayArg.abuffer == (Address) 0 ||
returnArrayArg.abuffer == (Address) USER_NIL)) {
returnArrayArg.abuffer = (Address) NIL;
newabuffer = (char *) NIL;
} else {
if (returnArrayArg.alength <= 0) {
free(newobuffer);
if (newibuffer != (char *) NIL) {
free(newibuffer);
}
status = GEN_INVALID_ARG;
break;
}
newabuffer = malloc(returnArrayArg.alength);
}
status = Recov_ReturnObjects(returnArrayArg.typeID,
&returnArrayArg.olength, newobuffer,
&returnArrayArg.ilength,
newibuffer, &returnArrayArg.alength, newabuffer);
if (status != SUCCESS) {
free(newobuffer);
if (newibuffer != (char *) NIL) {
free(newibuffer);
}
if (newabuffer != (char *) NIL) {
free(newabuffer);
}
break;
}
status = Vm_CopyOut(sizeof (int),
(Address) &returnArrayArg.olength,
(Address) &(((Recov_ReturnArrayArgs *)
argPtr)->olength));
if (status != SUCCESS) {
free(newobuffer);
if (newibuffer != (char *) NIL) {
free(newibuffer);
}
if (newabuffer != (char *) NIL) {
free(newabuffer);
}
break;
}
status = Vm_CopyOut(returnArrayArg.olength,
(Address) newobuffer,
(Address) (((Recov_ReturnArrayArgs *)
argPtr)->obuffer));
if (status != SUCCESS) {
free(newobuffer);
if (newibuffer != (char *) NIL) {
free(newibuffer);
}
if (newabuffer != (char *) NIL) {
free(newabuffer);
}
break;
}
if (newibuffer != (char *) NIL) {
status = Vm_CopyOut(sizeof (int),
(Address) &returnArrayArg.ilength, (Address)
&(((Recov_ReturnArrayArgs *) argPtr)->ilength));
if (status != SUCCESS) {
free(newobuffer);
free(newibuffer);
if (newabuffer != (char *) NIL) {
free(newabuffer);
}
break;
}
status = Vm_CopyOut(returnArrayArg.ilength,
(Address) newibuffer,
(Address)
(((Recov_ReturnArrayArgs *) argPtr)->ibuffer));
if (status != SUCCESS) {
free(newobuffer);
free(newibuffer);
if (newabuffer != (char *) NIL) {
free(newabuffer);
}
break;
}
}
if (newabuffer != (char *) NIL) {
status = Vm_CopyOut(sizeof (int),
(Address) &returnArrayArg.alength, (Address)
&(((Recov_ReturnArrayArgs *) argPtr)->alength));
if (status != SUCCESS) {
free(newobuffer);
if (newibuffer != (char *) NIL) {
free(newibuffer);
}
free(newabuffer);
break;
}
status = Vm_CopyOut(returnArrayArg.alength,
(Address) newabuffer,
(Address)
(((Recov_ReturnArrayArgs *) argPtr)->abuffer));
}
free(newobuffer);
if (newibuffer != (char *) NIL) {
free(newibuffer);
}
if (newabuffer != (char *) NIL) {
free(newabuffer);
}
break;
}
case RECOV_RETURN_CONTENTS: {
char *newbuffer;
int length;
status = Vm_CopyIn(sizeof (returnContentsArg), argPtr,
(Address) &returnContentsArg);
if (status != SUCCESS) {
break;
}
if ((returnContentsArg.buffer == (Address) NIL ||
returnContentsArg.buffer == (Address) 0 ||
returnContentsArg.buffer == (Address) USER_NIL)) {
status = GEN_INVALID_ARG;
break;
}
length = returnContentsArg.length;
newbuffer = malloc(length);
status = Recov_ReturnContents(&length, newbuffer);
if (status != SUCCESS) {
free(newbuffer);
break;
}
status = Vm_CopyOut(sizeof (int), (Address) &length,
(Address) &(((Recov_ReturnTableArgs *)
argPtr)->length));
if (status != SUCCESS) {
free(newbuffer);
break;
}
status = Vm_CopyOut(length, (Address) newbuffer,
(Address) (((Recov_ReturnTableArgs *) argPtr)->buffer));
break;
}
case RECOV_GET_OBJECT_SIZE: {
status = Vm_CopyIn(sizeof (getObjectSizeArg), argPtr,
(Address) &getObjectSizeArg);
if (status != SUCCESS) {
break;
}
getObjectSizeArg.objectSize =
Recov_GetObjectSize(getObjectSizeArg.typeID);
if (getObjectSizeArg.objectSize == -1) {
status = GEN_INVALID_ARG;
break;
}
status = Vm_CopyOut(sizeof (getObjectSizeArg),
(Address) &getObjectSizeArg, argPtr);
break;
}
case RECOV_MAP_TYPE: {
status = Vm_CopyIn(sizeof (mapTypeArg), argPtr,
(Address) &mapTypeArg);
if (status != SUCCESS) {
break;
}
status = Recov_MapType(mapTypeArg.applicationTypeID,
&(mapTypeArg.typeID));
if (status != SUCCESS) {
break;
}
status = Vm_CopyOut(sizeof (mapTypeArg),
(Address) &mapTypeArg, argPtr);
break;
}
case RECOV_MAP_OBJ_NUM: {
status = Vm_CopyIn(sizeof (mapObjNumArg), argPtr,
(Address) &mapObjNumArg);
if (status != SUCCESS) {
break;
}
status = Recov_MapObjectNum(mapObjNumArg.realTypeID,
mapObjNumArg.applicationObjectNum,
&(mapObjNumArg.realObjectNum));
if (status != SUCCESS) {
break;
}
status = Vm_CopyOut(sizeof (mapObjNumArg),
(Address) &mapObjNumArg, argPtr);
break;
}
case RECOV_TOGGLE_CHECKSUM: {
Recov_ToggleChecksum((int) argPtr);
status = SUCCESS;
break;
}
case RECOV_BULK_REOPEN: {
recov_BulkHandles = TRUE;
status = SUCCESS;
break;
}
case RECOV_SINGLE_REOPEN: {
recov_BulkHandles = FALSE;
status = SUCCESS;
break;
}
case RECOV_IGNORE_CLEAN: {
if (recov_SkipCleanFiles) {
printf("Cannot both skip and ignore reopening clean files.\n");
status = FAILURE;
} else {
recov_IgnoreCleanFiles = TRUE;
status = SUCCESS;
}
break;
}
case RECOV_REOPEN_CLEAN: {
recov_IgnoreCleanFiles = FALSE;
recov_SkipCleanFiles = FALSE;
status = SUCCESS;
break;
}
case RECOV_SKIP_CLEAN: {
if (recov_IgnoreCleanFiles) {
printf("Cannot both skip and ignore reopening clean files.\n");
status = FAILURE;
} else {
recov_SkipCleanFiles = TRUE;
status = SUCCESS;
}
break;
}
case RECOV_DO_SERVER_DRIVEN: {
recov_ClientIgnoreServerDriven = FALSE;
printf("Client is now responding to server-driven recovery.\n");
status = SUCCESS;
break;
}
case RECOV_NO_SERVER_DRIVEN: {
recov_ClientIgnoreServerDriven = TRUE;
printf("Client is now ignoring server-driven recovery.\n");
status = SUCCESS;
break;
}
case RECOV_PRINT_SIZE: {
int objSize;
objSize = (int) argPtr;
Recov_PrintSpace(objSize);
status = SUCCESS;
break;
}
default:
status = GEN_INVALID_ARG;
break;
}
return status;
}